#include <stdint.h>
#include <string.h>
#include <bsl_sal.h>
#include <bsl_obj.h>
#include <bsl_errno.h>
#include <bsl_params.h>
#include <bsl_err_internal.h>
#include <crypt_algid.h>
#include <crypt_errno.h>
#include <crypt_eal_implprovider.h>
#include <crypt_eal_provider.h>
#include <crypt_eal_rand.h>
#include <crypt_provider.h>
#include <crypt_default_provderimpl.h>
#include <crypt_params_key.h>
#include <hitls_crypt_type.h>
#include <hitls_cert_type.h>
#include <hitls_type.h>

#include "kaev1_dh.h"
#include "kaev1_digests.h"
#include "kaev1_modes.h"
#include "kaev1_rsa.h"
#include "kaev1_provider_impl.h"

#define NEW_PARA_ALGID (BSL_CID_MAX + 1)
#define NEW_PKEY_ALGID (BSL_CID_MAX + 2)

#define NEW_SIGN_HASH_ALGID (BSL_CID_MAX + 3)
#define NEW_HASH_ALGID (BSL_CID_MAX + 4)

void *KAE_TestPkeyMgmt_DefaultNewCtx(void *provCtx, int32_t algId)
{
    (void)provCtx;
    void *pkeyCtx = NULL;
    switch (algId) {
        case CRYPT_PKEY_RSA:
            pkeyCtx = KAE_RSA_NewCtx();
            break;
        case CRYPT_PKEY_DH:
            pkeyCtx = KAE_DH_NewCtx();
            break;
        case NEW_PKEY_ALGID:
            pkeyCtx = KAE_DH_NewCtx();
            break;
    }
    if (pkeyCtx == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_NOT_SUPPORT);
        return NULL;
    }
    return pkeyCtx;
};

int32_t KAE_TestPkeyMgmt_Ctrl(KAE_DH_Ctx *ctx, int32_t opt, void *val, uint32_t len)
{
    (void) len;

    if (ctx == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    switch (opt) {
        case CRYPT_CTRL_GET_PARAID:
            *((int32_t *)val) = NEW_PARA_ALGID;
            break;
        case CRYPT_CTRL_GET_BITS:
            *((uint32_t *)val) = 2048;
            break;
        case CRYPT_CTRL_GET_SECBITS:
            *((uint32_t *)val) = 2048;
            break;
        case CRYPT_CTRL_SET_PARA_BY_ID:
            if (*((int32_t *)val) != CRYPT_DH_RFC3526_2048 && *((int32_t *)val) != NEW_PARA_ALGID) {
                return CRYPT_INVALID_ARG;
            }
            return KAE_DH_SetParamById(ctx, CRYPT_DH_RFC3526_2048);
        default:
            break;
    }
    BSL_ERR_PUSH_ERROR(CRYPT_DH_UNSUPPORTED_CTRL_OPTION);
    return CRYPT_DH_UNSUPPORTED_CTRL_OPTION;
}

static void RandFunc(uint8_t *randNum, uint32_t randLen)
{
    for (uint32_t i = 0; i < randLen; i++) {
        randNum[i] = (uint8_t)(rand() % 255);
    }
}

void *TEST_DRBG_RandNewCtx(void *provCtx, int32_t algId, BSL_Param *param)
{
    (void)provCtx;
    (void)algId;
    (void)param;
    return malloc(1);
}

int32_t TEST_DRBG_Instantiate(void *ctx, const uint8_t *person, uint32_t persLen, BSL_Param *param)
{
    (void)ctx;
    (void)person;
    (void)persLen;
    (void)param;
    return CRYPT_SUCCESS;
}

int32_t TEST_DRBG_Uninstantiate(void *ctx)
{
    (void)ctx;
    return CRYPT_SUCCESS;
}

int32_t TEST_DRBG_Generate(void *ctx, uint8_t *out, uint32_t outLen,
    const uint8_t *adin, uint32_t adinLen,  BSL_Param *param)
{
    (void)ctx;
    (void)adin;
    (void)adinLen;
    (void)param;
    RandFunc(out, outLen);
    return CRYPT_SUCCESS;
}

int32_t TEST_DRBG_Reseed(void *ctx, const uint8_t *adin, uint32_t adinLen, BSL_Param *param)
{
    (void)ctx;
    (void)adin;
    (void)adinLen;
    (void)param;
    return CRYPT_SUCCESS;
}

int32_t TEST_DRBG_Ctrl(void *ctx, int32_t cmd, void *val, uint32_t valLen)
{
    (void)ctx;
    (void)cmd;
    (void)val;
    (void)valLen;
    return CRYPT_SUCCESS;
}

void TEST_DRBG_Free(void *ctx)
{
    free(ctx);
}

const CRYPT_EAL_Func g_testRand[] = {
    {CRYPT_EAL_IMPLRAND_DRBGNEWCTX, (CRYPT_EAL_ImplRandDrbgNewCtx)TEST_DRBG_RandNewCtx},
    {CRYPT_EAL_IMPLRAND_DRBGINST, (CRYPT_EAL_ImplRandDrbgInst)TEST_DRBG_Instantiate},
    {CRYPT_EAL_IMPLRAND_DRBGUNINST, (CRYPT_EAL_ImplRandDrbgUnInst)TEST_DRBG_Uninstantiate},
    {CRYPT_EAL_IMPLRAND_DRBGGEN, (CRYPT_EAL_ImplRandDrbgGen)TEST_DRBG_Generate},
    {CRYPT_EAL_IMPLRAND_DRBGRESEED, (CRYPT_EAL_ImplRandDrbgReSeed)TEST_DRBG_Reseed},
    {CRYPT_EAL_IMPLRAND_DRBGCTRL, (CRYPT_EAL_ImplRandDrbgCtrl)TEST_DRBG_Ctrl},
    {CRYPT_EAL_IMPLRAND_DRBGFREECTX, (CRYPT_EAL_ImplRandDrbgFreeCtx)TEST_DRBG_Free},
    CRYPT_EAL_FUNC_END,
};

const CRYPT_EAL_Func testRsaMgmt[] = {
    {CRYPT_EAL_IMPLPKEYMGMT_NEWCTX, KAE_TestPkeyMgmt_DefaultNewCtx},
    {CRYPT_EAL_IMPLPKEYMGMT_SETPARAM, KAE_RSA_SetPara},
    {CRYPT_EAL_IMPLPKEYMGMT_GENKEY, KAE_RSA_GenKey},
    {CRYPT_EAL_IMPLPKEYMGMT_SETPRV, KAE_RSA_SetPrv},
    {CRYPT_EAL_IMPLPKEYMGMT_SETPUB, KAE_RSA_SetPub},
    {CRYPT_EAL_IMPLPKEYMGMT_GETPRV, KAE_RSA_GetPrv},
    {CRYPT_EAL_IMPLPKEYMGMT_GETPUB, KAE_RSA_GetPub},
    {CRYPT_EAL_IMPLPKEYMGMT_DUPCTX, KAE_RSA_DupCtx},
    {CRYPT_EAL_IMPLPKEYMGMT_CHECK, NULL},
    {CRYPT_EAL_IMPLPKEYMGMT_COMPARE, KAE_RSA_Cmp},
    {CRYPT_EAL_IMPLPKEYMGMT_CTRL, KAE_RSA_Ctrl},
    {CRYPT_EAL_IMPLPKEYMGMT_FREECTX, KAE_RSA_Free},
    CRYPT_EAL_FUNC_END,
};

const CRYPT_EAL_Func testDhMgmt[] = {
    {CRYPT_EAL_IMPLPKEYMGMT_NEWCTX, KAE_TestPkeyMgmt_DefaultNewCtx},
    {CRYPT_EAL_IMPLPKEYMGMT_SETPARAM, KAE_DH_SetPara},
    {CRYPT_EAL_IMPLPKEYMGMT_GETPARAM, KAE_DH_GetPara},
    {CRYPT_EAL_IMPLPKEYMGMT_GENKEY, KAE_DH_Gen},
    {CRYPT_EAL_IMPLPKEYMGMT_SETPRV, KAE_DH_SetPrvKey},
    {CRYPT_EAL_IMPLPKEYMGMT_SETPUB, KAE_DH_SetPubKey},
    {CRYPT_EAL_IMPLPKEYMGMT_GETPRV, KAE_DH_GetPrvKey},
    {CRYPT_EAL_IMPLPKEYMGMT_GETPUB, KAE_DH_GetPubKey},
    {CRYPT_EAL_IMPLPKEYMGMT_DUPCTX, KAE_DH_DupCtx},
    {CRYPT_EAL_IMPLPKEYMGMT_CHECK, NULL},
    {CRYPT_EAL_IMPLPKEYMGMT_COMPARE, KAE_DH_Cmp},
    {CRYPT_EAL_IMPLPKEYMGMT_CTRL, KAE_TestPkeyMgmt_Ctrl},
    {CRYPT_EAL_IMPLPKEYMGMT_FREECTX, KAE_DH_Free},
    CRYPT_EAL_FUNC_END,
};

const CRYPT_EAL_Func testDhExch[] = {
    {CRYPT_EAL_IMPLPKEYEXCH_EXCH, KAE_DH_ComputeShareKey},
    CRYPT_EAL_FUNC_END
};

const CRYPT_EAL_Func testRsaSign[] = {
    {CRYPT_EAL_IMPLPKEYSIGN_SIGN, KAE_RSA_Sign},
    {CRYPT_EAL_IMPLPKEYSIGN_VERIFY, KAE_RSA_Verify},
    CRYPT_EAL_FUNC_END,
};

static CRYPT_EAL_AlgInfo testKeyMgmt[] = {
    {CRYPT_PKEY_RSA, testRsaMgmt, "provider=tls_provider"},
    {NEW_PKEY_ALGID, testDhMgmt, "provider=tls_provider"},
    CRYPT_EAL_ALGINFO_END
};

static CRYPT_EAL_AlgInfo testKeyExch[] = {
    {NEW_PKEY_ALGID, testDhExch, "provider=tls_provider"},
    CRYPT_EAL_ALGINFO_END
};

static CRYPT_EAL_AlgInfo testSigns[] = {
    {CRYPT_PKEY_RSA, testRsaSign, "provider=tls_provider"},
    CRYPT_EAL_ALGINFO_END
};

static CRYPT_EAL_AlgInfo testRands[] = {
    {CRYPT_RAND_SHA1, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_SHA224, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_SHA256, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_SHA384, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_SHA512, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_HMAC_SHA1, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_HMAC_SHA224, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_HMAC_SHA256, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_HMAC_SHA384, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_HMAC_SHA512, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_AES128_CTR, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_AES192_CTR, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_AES256_CTR, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_AES128_CTR_DF, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_AES192_CTR_DF, g_testRand, "provider=tls_provider"},
    {CRYPT_RAND_AES256_CTR_DF, g_testRand, "provider=tls_provider"},
    CRYPT_EAL_ALGINFO_END
};

static CRYPT_EAL_AlgInfo testEalDecoders[] = {
    {BSL_CID_DECODE_UNKNOWN, kaeEalPem2Der,
        "provider=default, inFormat=PEM, outFormat=ASN1"},
    {BSL_CID_DECODE_UNKNOWN, kaeEalPrvP8Enc2P8,
        "provider=default, inFormat=ASN1, inType=PRIKEY_PKCS8_ENCRYPT, outFormat=ASN1, outType=PRIKEY_PKCS8_UNENCRYPT"},
    {CRYPT_PKEY_RSA, kaeEalRsaPrvDer2Key,
        "provider=default, inFormat=ASN1, inType=PRIKEY_RSA, outFormat=OBJECT, outType=LOW_KEY"},
    {CRYPT_PKEY_RSA, kaeEalRsaPubDer2Key,
        "provider=default, inFormat=ASN1, inType=PUBKEY_RSA, outFormat=OBJECT, outType=LOW_KEY"},
    {CRYPT_PKEY_RSA, kaeEalP8Der2RsaKey,
        "provider=default, inFormat=ASN1, inType=PRIKEY_PKCS8_UNENCRYPT, outFormat=OBJECT, outType=LOW_KEY"},
    {CRYPT_PKEY_RSA, kaeEalSubPubKeyDer2RsaKey,
        "provider=default, inFormat=ASN1, inType=PUBKEY_SUBKEY, outFormat=OBJECT, outType=LOW_KEY"},
    {CRYPT_PKEY_RSA, kaeEalSubPubKeyWithoutSeqDer2RsaKey,
        "provider=default, inFormat=ASN1, inType=PUBKEY_SUBKEY_WITHOUT_SEQ, outFormat=OBJECT, outType=LOW_KEY"},
    {BSL_CID_DECODE_UNKNOWN, kaeEalLowKeyObject2PkeyObject,
        "provider=default, inFormat=OBJECT, inType=LOW_KEY, outFormat=OBJECT, outType=HIGH_KEY"},
    CRYPT_EAL_ALGINFO_END
};

#define TLS_GROUP_PARAM_COUNT 11
#define TLS_SIGN_SCHEME_PARAM_COUNT 18
typedef struct {
    const char *name;           // group name
    int32_t paraId;             // parameter id CRYPT_PKEY_ParaId
    int32_t algId;              // algorithm id CRYPT_PKEY_AlgId
    int32_t secBits;           // security bits
    uint16_t groupId;           // iana group id, HITLS_NamedGroup
    int32_t pubkeyLen;         // public key length(CH keyshare / SH keyshare)
    int32_t sharedkeyLen;      // shared key length
    int32_t ciphertextLen;     // ciphertext length(SH keyshare)
    uint32_t versionBits;       // TLS_VERSION_MASK
    bool isKem;                // true: KEM, false: KEX
} TLS_GroupInfo;

static const TLS_GroupInfo g_tlsGroupInfo[] = {
    {
        "test_dh_group",
        NEW_PARA_ALGID,      // paraId
        NEW_PKEY_ALGID,      // algId
        112, // secBits
        503, // groupId
        256, 256, 0, // pubkeyLen=256, sharedkeyLen=256 (2048 bits)
        TLS12_VERSION_BIT | TLS13_VERSION_BIT, // versionBits
        false
    },
};

static int32_t BuildTlsGroupParam(const TLS_GroupInfo *groupInfo, BSL_Param *param)
{
    int32_t ret = BSL_PARAM_InitValue(&param[0], CRYPT_PARAM_CAP_TLS_GROUP_IANA_GROUP_NAME, BSL_PARAM_TYPE_OCTETS_PTR,
        (void *)(uintptr_t)groupInfo->name, (uint32_t)strlen(groupInfo->name));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[1], CRYPT_PARAM_CAP_TLS_GROUP_IANA_GROUP_ID, BSL_PARAM_TYPE_UINT16,
       (void *)(uintptr_t)&(groupInfo->groupId), sizeof(groupInfo->groupId));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[2], CRYPT_PARAM_CAP_TLS_GROUP_PARA_ID, BSL_PARAM_TYPE_INT32,
        (void *)(uintptr_t)&(groupInfo->paraId), sizeof(groupInfo->paraId));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[3], CRYPT_PARAM_CAP_TLS_GROUP_ALG_ID, BSL_PARAM_TYPE_INT32,
        (void *)(uintptr_t)&(groupInfo->algId), sizeof(groupInfo->algId));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[4], CRYPT_PARAM_CAP_TLS_GROUP_SEC_BITS, BSL_PARAM_TYPE_INT32,
        (void *)(uintptr_t)&(groupInfo->secBits), sizeof(groupInfo->secBits));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[5], CRYPT_PARAM_CAP_TLS_GROUP_VERSION_BITS, BSL_PARAM_TYPE_UINT32,
        (void *)(uintptr_t)&(groupInfo->versionBits), sizeof(groupInfo->versionBits));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[6], CRYPT_PARAM_CAP_TLS_GROUP_IS_KEM, BSL_PARAM_TYPE_BOOL,
        (void *)(uintptr_t)&(groupInfo->isKem), sizeof(groupInfo->isKem));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[7], CRYPT_PARAM_CAP_TLS_GROUP_PUBKEY_LEN, BSL_PARAM_TYPE_INT32,
        (void *)(uintptr_t)&(groupInfo->pubkeyLen), sizeof(groupInfo->pubkeyLen));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[8], CRYPT_PARAM_CAP_TLS_GROUP_SHAREDKEY_LEN, BSL_PARAM_TYPE_INT32,
        (void *)(uintptr_t)&(groupInfo->sharedkeyLen), sizeof(groupInfo->sharedkeyLen));
    if (ret != BSL_SUCCESS) {
        return ret;
    }
    ret = BSL_PARAM_InitValue(&param[9], CRYPT_PARAM_CAP_TLS_GROUP_CIPHERTEXT_LEN, BSL_PARAM_TYPE_INT32,
        (void *)(uintptr_t)&(groupInfo->ciphertextLen), sizeof(groupInfo->ciphertextLen));
    if (ret != BSL_SUCCESS) {
        return ret;
    }

    return BSL_SUCCESS;
}

static int32_t TestGroupCaps(CRYPT_EAL_ProcessFuncCb cb, void *args)
{
    for (size_t i = 0; i < sizeof(g_tlsGroupInfo) / sizeof(g_tlsGroupInfo[0]); i++) {
        BSL_Param param[TLS_GROUP_PARAM_COUNT] = {0};
        int32_t ret = BuildTlsGroupParam(&g_tlsGroupInfo[i], param);
        if (ret != BSL_SUCCESS) {
            return ret;
        }
        ret = cb(param, args);
        if (ret != CRYPT_SUCCESS) {
            return ret;
        }
    }
    return CRYPT_SUCCESS;
}

static int32_t TestCryptGetSignAlgCaps(CRYPT_EAL_ProcessFuncCb cb, void *args)
{
    if (cb == NULL) {
        return CRYPT_NULL_INPUT;
    }
    uint16_t signatureScheme = 23333;
    int32_t keyType = CRYPT_PKEY_RSA;
    int32_t paraId = CRYPT_PKEY_PARAID_MAX;
    int32_t signHashAlgId = BSL_CID_SHA256WITHRSAENCRYPTION;
    int32_t signAlgId = CRYPT_PKEY_RSA;
    int32_t hashAlgId = CRYPT_MD_SHA256;
    int32_t secBits = 2048;
    uint32_t certVersionBits = TLS12_VERSION_BIT | TLS13_VERSION_BIT;
    uint32_t chainVersionBits = TLS12_VERSION_BIT | TLS13_VERSION_BIT;
    BSL_Param param[] = {
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_IANA_SIGN_NAME,
            BSL_PARAM_TYPE_OCTETS_PTR,
            (void *)(uintptr_t)"test_rsa_sign",
            (uint32_t)strlen("test_rsa_sign"),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_IANA_SIGN_ID,
            BSL_PARAM_TYPE_UINT16,
            (void *)(uintptr_t)&(signatureScheme),
            sizeof(uint16_t),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_KEY_TYPE,
            BSL_PARAM_TYPE_INT32,
            (void *)(uintptr_t)&(keyType),
            sizeof(keyType),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_PARA_ID,
            BSL_PARAM_TYPE_INT32,
            (void *)(uintptr_t)&(paraId),
            sizeof(paraId),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_SIGNWITHMD_ID,
            BSL_PARAM_TYPE_INT32,
            (void *)(uintptr_t)&(signHashAlgId),
            sizeof(signHashAlgId),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_SIGNWITHMD_OID,
            BSL_PARAM_TYPE_OCTETS_PTR,
            (void *)(uintptr_t)"\52\206\110\206\367\15\1\1\13", // 68 20 36 3F 2D
            (uint32_t)strlen("\52\206\110\206\367\15\1\1\13"),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_SIGNWITHMD_NAME,
            BSL_PARAM_TYPE_OCTETS_PTR,
            (void *)(uintptr_t)"SHA256WITHRSA",
            (uint32_t)strlen("SHA256WITHRSA"),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_SIGN_ID,
            BSL_PARAM_TYPE_INT32,
            (void *)(uintptr_t)&(signAlgId),
            sizeof(signAlgId),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_MD_ID,
            BSL_PARAM_TYPE_INT32,
            (void *)(uintptr_t)&(hashAlgId),
            sizeof(hashAlgId),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_MD_OID,
            BSL_PARAM_TYPE_OCTETS_PTR,
            (void *)(uintptr_t)"\140\206\110\1\145\3\4\2\1",
            (uint32_t)strlen("\140\206\110\1\145\3\4\2\1"),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_MD_NAME,
            BSL_PARAM_TYPE_OCTETS_PTR,
            (void *)(uintptr_t)"SHA256",
            (uint32_t)strlen("SHA256"),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_SEC_BITS,
            BSL_PARAM_TYPE_INT32,
            (void *)(uintptr_t)&(secBits),
            sizeof(secBits),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_CHAIN_VERSION_BITS,
            BSL_PARAM_TYPE_UINT32,
            (void *)(uintptr_t)&(chainVersionBits),
            sizeof(chainVersionBits),
            0,
        },
        {
            CRYPT_PARAM_CAP_TLS_SIGNALG_CERT_VERSION_BITS,
            BSL_PARAM_TYPE_UINT32,
            (void *)(uintptr_t)&(certVersionBits),
            sizeof(certVersionBits),
            0,
        }
    };
    return cb(param, args);
}

static int32_t TestProvGetCaps(void *provCtx, int32_t cmd, CRYPT_EAL_ProcessFuncCb cb, void *args)
{
    (void) provCtx;
    if (cb == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }
    switch (cmd) {
        case CRYPT_EAL_GET_GROUP_CAP:
            return TestGroupCaps(cb, args);
        case CRYPT_EAL_GET_SIGALG_CAP:
            return TestCryptGetSignAlgCaps(cb, args);
        default:
            BSL_ERR_PUSH_ERROR(CRYPT_NOT_SUPPORT);
            return CRYPT_NOT_SUPPORT;
    }
}

static int32_t TestProvQuery(void *provCtx, int32_t operaId, CRYPT_EAL_AlgInfo **algInfos)
{
    (void)provCtx;
    switch (operaId) {
        case CRYPT_EAL_OPERAID_KEYMGMT:
            *algInfos = testKeyMgmt;
            break;
        case CRYPT_EAL_OPERAID_KEYEXCH:
            *algInfos = testKeyExch;
            break;
        case CRYPT_EAL_OPERAID_RAND:
            *algInfos = testRands;
            break;
        case CRYPT_EAL_OPERAID_SIGN:
            *algInfos = testSigns;
            break;
        case CRYPT_EAL_OPERAID_DECODER:
            *algInfos = testEalDecoders;
            break;
        default:
            return CRYPT_NOT_SUPPORT;
    }
    return CRYPT_SUCCESS;
}

static void TestProvFree(void *provCtx)
{
    (void) provCtx;
    WdDHDestroyQnodePool();
    WdDigestsDestroyQnodePool();
    WdModesDestroyQnodePool();
    WdRsaDestroyQnodePool();
}

static CRYPT_EAL_Func TestProvOutFuncs[] = {
    {CRYPT_EAL_PROVCB_QUERY, TestProvQuery},
    {CRYPT_EAL_PROVCB_FREE, TestProvFree},
    {CRYPT_EAL_PROVCB_CTRL, NULL},
    {CRYPT_EAL_PROVCB_GETCAPS, TestProvGetCaps},
    CRYPT_EAL_FUNC_END
};

int32_t CRYPT_EAL_ProviderInit(CRYPT_EAL_ProvMgrCtx *mgrCtx, BSL_Param *param,
    CRYPT_EAL_Func *capFuncs, CRYPT_EAL_Func **outFuncs, void **provCtx)
{
    (void) provCtx;
    (void) mgrCtx;
    (void) param;
    (void) capFuncs;

    int32_t ret = CRYPT_SUCCESS;
    ret = WdDHInitQnodePool();
    if (ret != CRYPT_SUCCESS) {
        goto EXIT;
    }

    ret = WdDigestsInitQnodePool();
    if (ret != CRYPT_SUCCESS) {
        goto EXIT;
    }

    ret = WdModesInitQnodePool();
    if (ret != CRYPT_SUCCESS) {
        goto EXIT;
    }

    ret = WdRsaInitQnodePool();
    if (ret != CRYPT_SUCCESS) {
        goto EXIT;
    }

    *outFuncs = TestProvOutFuncs;
    return CRYPT_SUCCESS;
EXIT:
    TestProvFree(NULL);
    return ret;
}